
#ifndef __TCP_SERVER_H
#define __TCP_SERVER_H

#include "netgeneral.h"
#include <openssl/err.h>
#include <apr_atomic.h>
#include <apr_file_io.h>
#include <apr_poll.h>
#include <apr_portable.h>
#include "../aprtools/APRMutex.h"
#include "../aprtools/APRBucketBrigade.h"

#define PENDING_CONNECTIONS 8

#define SERVERSTAGE_INACTIVE   0
#define SERVERSTAGE_RECEIVING  1
#define SERVERSTAGE_READING    2
#define SERVERSTAGE_WRITING    3
#define SERVERSTAGE_SENDING    4

// 0->1 ServerListener
// 1->2 Session
// 2->3 Session
// 3->4 Session
// 4->0 ServerListener

typedef struct clientpipes
{
   apr_uint32_t stage;
   apr_pool_t *localmp;
   apr_sockaddr_t *cliaddr;
   APRBucketBrigade *recv_to_handler;
   APRBucketBrigade *handler_to_send;
   apr_socket_t *clisock;
   APRMutex *sessionstart;
   APRMutex *waiting;
} ClientPipes;

// Ugliest thing in the universe
typedef void *(*functor)(apr_thread_t *, void *);

class TCPServer
{
   public:
      TCPServer(int inoofthreads, int iportno, const char *ihostname, apr_pool_t *upperpool);
      virtual ~TCPServer();
      int StartListeningThread();
      int StartSessionThreads();
      void SocketAccept(apr_pollset_t *pollset, apr_socket_t *lsock, apr_pool_t *mp);
      static void *ServerListen(apr_thread_t *tthread, void *vthis);
      static void *ClientHandler(apr_thread_t *tthread, void *args);
      virtual functor GetClientHandlerFunction() const { return (functor)(&ClientHandler); }
      int JoinThreads();
      apr_socket_t *CreateListeningSocket(apr_pool_t *mp);
      const char *StaticStringGetClientAddress(int threadid);
      static void ParseHeaderBody(char *data, char **header, char **body);
      int IsListening() { return (!listenstop); }
      ClientPipes *pipearray;
      apr_thread_t *listening_thread;
      apr_thread_t **session_threads;
      apr_threadattr_t *listening_attr;
      apr_threadattr_t **session_threadattrs;
      apr_pool_t *mp;
      int noofthreads;
   private:
      char *hostname;
      int portno;
      int timeout;
      int listenstop;
   protected:
      int sessionstop;
};

#endif
